﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Json;

namespace EcoSystem
{
    public class ConfigDefineAppService : CrudAppService<
         ConfigDefine,
         ConfigDefineDto,
         Guid,
         GetConfigDefineInput,
         CreateOrUpdateConfigDefineDto,
         CreateOrUpdateConfigDefineDto>, IConfigDefineAppService
    {
        private readonly IConfigSettingAppService _configSettingAppService;
        private readonly IAuditingManager _auditingManager;
        public ConfigDefineAppService(
           IAuditingManager auditingManager,
            IRepository<ConfigDefine, Guid> repository, IConfigSettingAppService configSettingAppService)
            : base(repository)
        {
            _configSettingAppService = configSettingAppService;
            _auditingManager = auditingManager;
        }

        private bool CheckKeyExist(List<ConfigDefine> all, Guid id, string key, string category)
        {
            if (all.Any(x => x.Id != id && x.Key.Equals(key) && x.Category == category))
            {
                throw new UserFriendlyException($"key:{key}已存在，不能重复定义！");
            }
            return true;
        }

        private bool CheckKeyExist(Guid id, string key, string category)
        {
            if (Repository.AnyAsync(x => x.Id != id && x.Key.Equals(key) && x.Category == category).Result)
            {
                throw new UserFriendlyException($"key:{key}已存在，不能重复定义！");
            }
            return true;
        }

        public override async Task<ConfigDefineDto> CreateAsync(CreateOrUpdateConfigDefineDto input)
        {
            CheckKeyExist(Guid.Empty, input.Key, input.Category);
            var entity = ObjectMapper.Map<CreateOrUpdateConfigDefineDto, ConfigDefine>(input);
            EntityHelper.TrySetId(entity, () => GuidGenerator.Create());
            entity = await Repository.InsertAsync(entity);
            var result = ObjectMapper.Map<ConfigDefine, ConfigDefineDto>(entity);
            return result;
        }

        public override async Task<ConfigDefineDto> UpdateAsync(Guid id, CreateOrUpdateConfigDefineDto input)
        {
            CheckKeyExist(id, input.Key, input.Category);
            var entity = await Repository.FirstOrDefaultAsync(x => x.Id == id);
            if (entity == null)
            {
                throw new UserFriendlyException("需要修改的信息不存在");
            }
            entity = ObjectMapper.Map(input, entity);
            entity = await Repository.UpdateAsync(entity);
            var result = ObjectMapper.Map<ConfigDefine, ConfigDefineDto>(entity);
            return result;
        }

        public override async Task<ConfigDefineDto> GetAsync(Guid id)
        {
            var entity = await Repository.FirstOrDefaultAsync(x => x.Id == id);
            if (entity == null)
            {
                throw new UserFriendlyException("配置定义信息不存在");
            }
            var result = ObjectMapper.Map<ConfigDefine, ConfigDefineDto>(entity);
            result.KeyDefaultValue = entity.DefaultValue == null ? "" : JsonSerializer.Serialize(entity.DefaultValue);
            return result;
        }

        public override async Task<PagedResultDto<ConfigDefineDto>> GetListAsync(GetConfigDefineInput input)
        {
            var query = from a in (await Repository.GetQueryableAsync())
                        select a;
            query = query.WhereIf(!string.IsNullOrEmpty(input.Category), x => x.Category == input.Category)
                .WhereIf(!string.IsNullOrEmpty(input.Key), x => x.Key.Contains(input.Key));
            var total = await query.CountAsync();
            var list = await query.OrderBy(x => x.Category).Skip(input.SkipCount).Take(input.MaxResultCount).ToListAsync();
            var result = list.Select(x =>
            {
                var dto = ObjectMapper.Map<ConfigDefine, ConfigDefineDto>(x);
                dto.KeyDefaultValue = x.DefaultValue == null ? "" : JsonSerializer.Serialize(x.DefaultValue);
                return dto;
            }).ToList();
            return new PagedResultDto<ConfigDefineDto> { TotalCount = total, Items = result };
        }

        public override async Task DeleteAsync(Guid id)
        {
            var define = await Repository.FirstOrDefaultAsync(x => x.Id == id);
            if (define == null)
            {
                return;
            }
            await _configSettingAppService.DeleteForKeyAsync(define.Key);
            await base.DeleteAsync(id);
        }

        public async Task<bool> ConfigDefineMultiEditAsync(MultiConfigDefineDto input)
        {
            if (input == null || input.KeyConfigs == null || input.KeyConfigs.Count == 0)
            {
                throw new UserFriendlyException("配置定义信息不能为空");
            }
            if (input.KeyConfigs.Select(x => x.Key).Distinct().Count() != input.KeyConfigs.Count())
            {
                throw new UserFriendlyException("key不能重复");
            }
            var all = await (await Repository.GetQueryableAsync()).Where(x => x.Category == input.Category).ToListAsync();

            //获取已存在的配置定义信息
            var exists = all.FindAll(x => x.Category == input.Category);
            foreach (var config in input.KeyConfigs)
            {
                CheckKeyExist(all, config.Id, config.Key, input.Category);
                if (config.Id == Guid.Empty)
                {
                    ConfigDefine entity = new ConfigDefine
                    {
                        Category = input.Category,
                        ControlProperty = config.ControlProperty,
                        ControlType = config.ControlType,
                        DefaultValue = config.DefaultValue,
                        Key = config.Key,
                        KeyName = config.KeyName,
                        KeyType = config.KeyType,
                        SortIndex = config.SortIndex,
                    };
                    EntityHelper.TrySetId(entity, () => GuidGenerator.Create());
                    entity = await Repository.InsertAsync(entity, true);
                }
                else
                {
                    var entity = exists.FirstOrDefault(x => x.Id == config.Id);
                    if (entity != null)
                    {
                        entity.Category = input.Category;
                        entity.ControlProperty = config.ControlProperty;
                        entity.ControlType = config.ControlType;
                        entity.DefaultValue = config.DefaultValue;
                        entity.KeyType = config.KeyType;
                        entity.SortIndex = config.SortIndex;
                        entity = await Repository.UpdateAsync(entity, true);
                    }
                }
            }
            foreach (var item in exists)
            {
                if (input.KeyConfigs.Find(x => x.Id == item.Id) == null)
                {
                    await _configSettingAppService.DeleteForKeyAsync(item.Key);
                    await base.DeleteAsync(item.Id);
                }
            }
            return true;
        }

        public async Task<MultiConfigDefineDto> GetCategoryConfigDefineAsync(string category)
        {
            var exists = await (await Repository.GetQueryableAsync()).Where(x => x.Category == category).ToListAsync();
            if (exists.Count == 0)
            {
                return new MultiConfigDefineDto
                {
                    Category = category,
                    KeyConfigs = new List<KeyConfigDefineDto>(),
                };
            }
            return new MultiConfigDefineDto
            {
                Category = exists[0].Category,
                KeyConfigs = exists.ConvertAll(x => new KeyConfigDefineDto
                {
                    ControlProperty = x.ControlProperty,
                    ControlType = x.ControlType,
                    DefaultValue = x.DefaultValue,
                    Id = x.Id,
                    Key = x.Key,
                    KeyName = x.KeyName,
                    KeyType = x.KeyType
                })
            };
        }
    }
}
